package org.senseframework.support.open.api.service;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.senseframework.support.core.utils.DigestUtils;
import org.senseframework.support.core.utils.JSONUtils;
import org.senseframework.support.open.api.annotation.ServiceCache;
import org.senseframework.support.open.api.cache.CacheProvider;
import org.senseframework.support.open.api.exception.ApiException;
import org.senseframework.support.open.api.validate.Validate;
import org.senseframework.support.open.api.validate.ValidateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * lanjian
 */
public abstract class AbstractApiService<K extends Map> implements IApiService<K>, ApplicationContextAware {

    private ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    protected static Logger log = LoggerFactory.getLogger(AbstractApiService.class);


    //    @Resource
//    private SensitiveWordFilter sensitiveWordFilter;
    @Autowired
    private TokenGenerate tokenGenerate;

    //    @Autowired
    private RequestLog requestLog = null;

    public RequestLog getRequestLog() {
        return requestLog;
    }

    public void setRequestLog(RequestLog requestLog) {
        this.requestLog = requestLog;
    }

    @Autowired
    private BaseFiledValidate baseFiledValidate;

    public BaseFiledValidate getBaseFiledValidate() {
        return baseFiledValidate;
    }

    public void setBaseFiledValidate(BaseFiledValidate baseFiledValidate) {
        this.baseFiledValidate = baseFiledValidate;
    }

    public TokenGenerate getTokenGenerate() {
        return tokenGenerate;
    }

    public void setTokenGenerate(TokenGenerate tokenGenerate) {
        this.tokenGenerate = tokenGenerate;
    }

    public K handler(String service, String version, final String json, final String ipAddress, MultipartFile[] files, String sessionID, boolean encrypt) {
        if (applicationContext == null) {
            throw new RuntimeException("applicationContext not be null");
        }

        final Map request = JSONUtils.parseObject(json, HashMap.class);
        K k = null;
        String cacheInfo = null;
        try {
            request.put("ip", ipAddress);
            request.put("session", sessionID);
            Validate.goValidate(getClass(), request, files, tokenGenerate, baseFiledValidate, encrypt);
            if (getClass().isAnnotationPresent(ServiceCache.class) && getClass().isAnnotationPresent(Component.class)) {
                ServiceCache serviceCache = getClass().getAnnotation(ServiceCache.class);
                Component component = getClass().getAnnotation(Component.class);
                StringBuilder key = new StringBuilder("protocol_" + component.value() + "_");
                for (String _key : serviceCache.keys()) {
                    key.append(request.get(_key));
                }
                String md5Key = DigestUtils.md5(key.toString());
                CacheProvider cacheProvider = (CacheProvider) applicationContext.getBean(serviceCache.cacheProvider());
                if (cacheProvider == null) {
                    throw new ApiException("no cache provider register", ApiDefinition.INVALID_BIND_CODE);
                }
                String cache = cacheProvider.get(md5Key);
                if (StringUtils.isBlank(cache)) {
                    cacheInfo = key.toString() + "<" + md5Key + ">";
                    k = service(request, files);
                    cache = JSONUtils.toJSONString(k);
                    cacheProvider.set(md5Key, serviceCache.time(), cache);
                } else {
                    k = JSONUtils.parseObject(cache, HashMap.class);
                }
            } else {
                k = service(request, files);
            }
        } catch (ValidateException e) {
            throw e;
        } catch (ApiException e) {
            throw e;
        } catch (Exception ex) {
            log.info(getClass().getSimpleName() + " handler exception", ex);
            throw new ApiException(ex.getMessage(), ApiDefinition.FAIL_CODE);
        } finally {
            if (requestLog != null) {
                String _status = k == null ? "505" : String.valueOf(k.get("status"));
                try {
                    String agentId = formatString(request.get("leaderId"));
                    if (StringUtils.isBlank(agentId)) {
                        agentId = formatString(request.get("agentId"));
                    }
                    requestLog.saveLog(formatString(request.get("channel")), service, version, request, ipAddress, _status, k, cacheInfo, agentId);
                } catch (Exception e) {
                    log.info("insert request log fail,e.msg=" + e.getMessage(), e);
                }
            }
        }
        return k;
    }


    public List<String> formatList(Object obj) {
        return JSON.parseArray(formatString(obj), String.class);
    }

    public <T> List<T> formatList(Object obj, Class clazz) {
        return JSON.parseArray(formatString(obj), clazz);
    }

    public List<Integer> formatList2Int(Object obj) {
        return JSON.parseArray(formatString(obj), Integer.class);
    }


    public Float formatFloat(Object obj) {
        try {
            return Float.valueOf(formatString(obj));
        } catch (Exception e) {
            return null;
        }
    }

    public Float formatFloat(Object obj, Float d) {
        try {
            String o = formatString(obj);
            if (StringUtils.isBlank(o)) {
                return d;
            }
            return Float.valueOf(o);
        } catch (NumberFormatException e) {
            return d;
        }
    }

    public Integer formatInteger(Object obj) {
        try {
            return Integer.valueOf(formatString(obj));
        } catch (Exception e) {
            return null;
        }
    }

    public Integer formatInteger(Object obj, Integer d) {
        try {
            String o = formatString(obj);
            if (StringUtils.isBlank(o)) {
                return d;
            }
            return Integer.valueOf(o);
        } catch (NumberFormatException e) {
            return d;
        }
    }

    public Long formatLong(Object obj) {
        try {
            return Long.valueOf(formatString(obj));
        } catch (NumberFormatException e) {
            return null;
        }
    }

    public Long formatLong(Object obj, Long d) {
        try {
            String o = formatString(obj);
            if (StringUtils.isBlank(o)) {
                return d;
            }
            return Long.valueOf(o);
        } catch (NumberFormatException e) {
            return d;
        }
    }

    public Double formatDouble(Object obj) {
        try {
            return Double.valueOf(formatString(obj));
        } catch (Exception ex) {
            return null;
        }
    }

    public Double formatDouble(Object obj, Double d) {
        try {
            String o = formatString(obj);
            if (StringUtils.isBlank(o)) {
                return d;
            }
            return Double.valueOf(o);
        } catch (Exception ex) {
            return d;
        }
    }

    public String formatString(Object obj) {
        try {
            if (obj == null) {
                return null;
            }
            return String.valueOf(obj);
        } catch (Exception e) {
            return null;
        }
    }

    public String formatString(Object obj, String d) {
        try {
            if (obj == null) {
                return d;
            }
            return String.valueOf(obj);
        } catch (Exception e) {
            return d;
        }
    }

    public boolean formatBoolean(Object obj) {
        try {
            if (obj == null) {
                return false;
            }
            return Boolean.valueOf(formatString(obj));
        } catch (Exception e) {
            return false;
        }
    }


//    protected Application anaApplication(Map request) {
//        String ak = formatString(request.get("ak"));
//        String aid = formatString(request.get("appid"));
//        Application application = Application.build(Application.class).eq("apiKey", ak).eq("appid", aid).one();
//        if (application.getOpenStatus().equals(OpenStatus.closed)) {
//            throw new ApiException("应用被封禁", ApiDefinition.APP_ERROR_CLOSED);
//        }
//        return application;
//    }

//
//    public SensitiveWordFilter getSensitiveWordFilter() {
//        return sensitiveWordFilter;
//    }
//
//    public void setSensitiveWordFilter(SensitiveWordFilter sensitiveWordFilter) {
//        this.sensitiveWordFilter = sensitiveWordFilter;
//    }
}
